using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using LeisureCenter.Api;
using LeisureCenter.Api.Tools;
using LeisureCenter.Core;

namespace LeisureCenter.Playlist
{
    internal class ErrorMedia : BaseMedia
    {
        public ErrorMedia(string fileName, string errorMessage)
            : base(fileName)
        {
            loadingErrorMessage = errorMessage;
        }

        public override MediaKind Kind
        {
            get { return MediaKind.Unknown; }
        }
    }

    public abstract class BasePlaylistItem : Disposable, IPlaylistItem
    {
        protected bool played;
        protected IMedia _media;
        protected BasePlaylist _playlist;

        protected BasePlaylistItem(BasePlaylist playlist)
        {
            this._playlist = playlist;
        }

        protected abstract void CreateMedia();

        protected IMedia Media
        {
            get
            {
                if (_media == null)
                {
                    CreateMedia();
                    if (_media is IPositionableMedia)
                    {
                        ((IPositionableMedia)_media).PlayStateChange += new EventHandler<PlayStateChangeEventArgs>(PlaylistItem_PlayStateChange);
                        ((IPositionableMedia)_media).MediaEnded += new EventHandler(PlaylistItem_MediaEnded);
                    }
                    else
                        if (_media == null)
                        {
                            _media = new ErrorMedia("", @"no player were found to handle this media");
                        }
                }
                return _media;
            }
        }

        protected virtual void PlaylistItem_PlayStateChange(object sender, PlayStateChangeEventArgs e)
        {
        }

        protected virtual void PlaylistItem_MediaEnded(object sender, EventArgs e)
        {
            EventHandler temp = MediaEnded;
            if (temp != null)
            {
                temp(sender, e);
            }
        }

        #region IPlaylistItem Membres

        public abstract string Text { get; }

        public bool Played { get { return played; } set { this.played = value; } }

        public int Index
        {
            get
            {
                if (_playlist != null)
                    return _playlist.items.IndexOf(this);
                else
                    return -1;
            }
        }

        public void StepBackward()
        {
            Position -= (int)(Duration * 0.03);
        }

        public void StepForward()
        {
            Position += (int)(Duration * 0.03);
        }

        public void BigStepBackward()
        {
            Position -= (int)(Duration * 0.1);
        }

        public void BigStepForward()
        {
            Position += (int)(Duration * 0.1);
        }

        #endregion

        #region IMedia Membres

        public MediaKind Kind
        {
            get
            {
                if (Media != null)
                    return _media.Kind;
                else
                    return MediaKind.Unknown;
            }
        }

        public string FileName
        {
            get
            {
                if (Media != null)
                    return _media.FileName;
                else
                    return "";
            }
        }

        public MediaLoadingState LoadingState
        {
            get
            {
                // do no try to create the media here
                if (_media != null)
                    return _media.LoadingState;
                else
                    return MediaLoadingState.None;
            }
        }

        public string LoadingErrorMessage
        {
            get
            {
                // do no try to create the media here
                if (_media != null)
                    return _media.LoadingErrorMessage;
                else
                    return "";
            }
        }

        public void Preload()
        {
            if (Media != null)
                _media.Preload();
        }

        #endregion

        #region IPositionableMedia Membres

        public int Duration
        {
            get
            {
                if (Media is IPositionableMedia)
                    return ((IPositionableMedia)_media).Duration;
                else
                    return 0;
            }
        }

        public int Position
        {
            get
            {
                if (Media is IPositionableMedia)
                    return ((IPositionableMedia)_media).Position;
                else
                    return 0;
            }
            set
            {
                value = Math.Max(value, 0);
                if (Media is IPositionableMedia)
                    ((IPositionableMedia)_media).Position = value;
                if (_playlist != null)
                {
                    _playlist.playlistManager.SetPosition(value);
                }
            }
        }

        public MediaPlayState PlayState
        {
            get
            {
                if (Media is IPositionableMedia)
                    return ((IPositionableMedia)_media).PlayState;
                else
                    return MediaPlayState.Stopped;
            }
        }

        public virtual void Play()
        {
            if (Media is IPositionableMedia)
            {
                ((IPositionableMedia)_media).Play();
            }
        }

        public void Pause()
        {
            if (Media is IPositionableMedia)
                ((IPositionableMedia)_media).Pause();
        }

        public void PlayPause()
        {
            if (Media is IPositionableMedia)
                ((IPositionableMedia)_media).PlayPause();
        }

        public void Stop()
        {
            if (Media is IPositionableMedia)
                ((IPositionableMedia)_media).Stop();
        }

        public event EventHandler<PlayStateChangeEventArgs> PlayStateChange
        {
            add
            {
                if (Media is IPositionableMedia)
                    ((IPositionableMedia)_media).PlayStateChange += value;
            }
            remove
            {
                if (Media is IPositionableMedia)
                    ((IPositionableMedia)_media).PlayStateChange -= value;
            }
        }

        public event EventHandler MediaEnded;

        #endregion

        #region ISearchableMedia Membres

        public double PlayRate
        {
            get
            {
                if (Media is ISearchableMedia)
                    return ((ISearchableMedia)_media).PlayRate;
                else
                    return 1;
            }
        }

        public void FastForward()
        {
            if (Media is ISearchableMedia)
                ((ISearchableMedia)_media).FastForward();
            else
                StepForward();
        }

        public void FastReverse()
        {
            if (Media is ISearchableMedia)
                ((ISearchableMedia)_media).FastReverse();
            else
                StepBackward();
        }

        #endregion

        #region IVisualMedia Membres

        public bool FullScreen
        {
            get
            {
                if (Media is IVisualMedia)
                    return ((IVisualMedia)_media).FullScreen;
                else
                    return false;
            }
            set
            {
                if (Media is IVisualMedia)
                    ((IVisualMedia)_media).FullScreen = value;
            }
        }

        public MediaAspectRatio AspectRatio
        {
            get
            {
                if (Media is IVisualMedia)
                    return ((IVisualMedia)_media).AspectRatio;
                else
                    return MediaAspectRatio.Stretched;
            }
            set
            {
                if (Media is IVisualMedia)
                    ((IVisualMedia)_media).AspectRatio = value;
            }
        }

        public void SetPreviewArea(Control control, Rectangle rect)
        {
            if (Media is IVisualMedia)
                ((IVisualMedia)_media).SetPreviewArea(control, rect);
        }

        public void HidePreview()
        {
            if (Media is IVisualMedia)
                ((IVisualMedia)_media).HidePreview();
        }

        #endregion

        #region IControllableMedia Membres

        public bool HandleKey(Keys key)
        {
            if (Media is IControllableMedia)
                return ((IControllableMedia)_media).HandleKey(key);
            else
                return false;
        }

        #endregion

        protected override void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (this._media is IDisposable)
                    ((IDisposable)this._media).Dispose();
            }

            base.Dispose(disposing);
        }
    }

    public abstract class BasePlaylist : Disposable, IPlaylist, IEnumerable<IPlaylistItem>
    {
        internal DisposableList<IPlaylistItem> items = new DisposableList<IPlaylistItem>();
        internal PlaylistManager playlistManager;
        protected IPlaylistItem activePlaylistItem;
        protected IPlaylistItem activePlaylistItemStub = new PlaylistStubItem();

        protected BasePlaylist(PlaylistManager playlistManager)
        {
            this.playlistManager = playlistManager;
            playlistManager.PlayModeChanged += new EventHandler(playlistManager_PlayModeChanged);
        }

        protected override void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                (this.items as IDisposable).Dispose();
                playlistManager.PlayModeChanged -= new EventHandler(playlistManager_PlayModeChanged);
            }

            base.Dispose(disposing);
        }

        protected internal abstract void playlistManager_PlayModeChanged(object sender, EventArgs e);

        public event EventHandler BeforeActiveItemChange;
        public event EventHandler AfterActiveItemChange;

        #region IPlaylist Membres

        public IPlaylistItem this[int index]
        {
            get
            {
                if (index >= 0 && index < items.Count)
                    return items[index];
                else
                    return null;
            }
        }

        public int Count
        {
            get { return items.Count; }
        }

        public abstract void Previous();
        public abstract void Next();

        public virtual IPlaylistItem ActivePlaylistItem
        {
            get { return activePlaylistItem; }
            set 
            {
                if (this.activePlaylistItem != value)
                {
                    EventHandler temp = BeforeActiveItemChange;
                    if (temp != null)
                    {
                        temp(this, null);
                    }
                    activePlaylistItem = value;
                    temp = AfterActiveItemChange;
                    if (temp != null)
                    {
                        temp(this, null);
                    }
                }
            }
        }

        public abstract int ActivePlaylistItemIndex { get; set; }

        public IPlaylistItem ActivePlaylistItemOrStub
        {
            get
            {
                if (activePlaylistItem != null)
                    return activePlaylistItem;
                else
                    return activePlaylistItemStub;
            }
        }

        #endregion

        #region IEnumerable<IPlaylistItem> Membres

        public IEnumerator<IPlaylistItem> GetEnumerator()
        {
            return items.GetEnumerator();
        }

        #endregion

        #region IEnumerable Membres

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }

}
